/***********************************************************************************
* @ file    : imi_config.h
* @ author  : qinhj
* @ version : 1.0.1
* @ date    : 2020.03.30
* @Copyright (c) 2020 chuangmi inc.
* -----------------------------------------------------------------------------------
* @ note:
* 1. For c/cc/cpp file with WINDOWS, qualifiers "API_PUBLIC" and "API_PRIVATE" that
  used in h/hpp cant't be ommited.
* 2. For WINDOWS, func unexport by default, while for LINUX always visible as GLOBAL.
* 3. One can use "readelf -p .dynstr libxxx.so" to check symbols under linux.
* 4. One can use "strip" to remove LOCAL symbols in output libraries under linux.
* 5. For linux, attribute visibility "default" means always export, while "hidden"
  means unexport, and -fvisibility=hidden can only control other func's visibility.
* 6. For linux, one could search -fvisibility-inlines-hidden for more details.
************************************************************************************/

#ifndef __IMI_API_CONFIG_H__
#define __IMI_API_CONFIG_H__

#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
#define __WINDOWS__
#endif

// ATTRIBUTE: DEPRECATED
#if defined(__GNUC__) && ((__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1)))
#define DEPRECATED_ATTRIBUTE __attribute__((deprecated))
#define DEPRECATED_ATTRIBUTE_MSG(msg) __attribute__((deprecated))
#elif 1400 <= _MSC_VER // vs 2005 or higher
#define DEPRECATED_ATTRIBUTE __declspec(deprecated)
#define DEPRECATED_ATTRIBUTE_MSG(msg) __declspec(deprecated(msg))
#else
#define DEPRECATED_ATTRIBUTE
#endif

// ATTRIBUTE: EXPORT as PUBLIC
// ATTRIBUTE: cdecl/stdcall/fastcall/pascal
#ifdef __WINDOWS__

/*  When compiling for windows, we specify a specific calling convention to avoid issues where we are being called
    from a project with a different default calling convention.  For windows you have 2 define options:

    API_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
    API_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
    API_IMPORT_SYMBOLS - Define this if you want to dllimport symbol    */

/* export symbols by default, this is necessary for copy pasting the C and header file */
#if !defined(API_HIDE_SYMBOLS) && !defined(API_IMPORT_SYMBOLS) && !defined(API_EXPORT_SYMBOLS)
#define API_EXPORT_SYMBOLS
#endif

/*
    ==============================================================
     call rule  |  stack order  | stack cleaner |   description
    --------------------------------------------------------------
        cdecl   | right to left |     invoker   |  C Declaration
       stdcall  | right to left |     callee    |  Standard Call
      fastcall  | r2l(EDX->ECX) |     callee    |   By Compiler
       pascal   | left to right |     callee    | Pascal / Delphi
    ==============================================================
*/

#if defined(API_HIDE_SYMBOLS)
#define API_PUBLIC(type)            type // __cdecl(default) __stdcall ...
#define API_PUBLIC_EXT(type, call)  type __##call
#elif defined(API_EXPORT_SYMBOLS)
#define API_PUBLIC(type)            __declspec(dllexport) type // __cdecl __stdcall
#define API_PUBLIC_EXT(type, call)  __declspec(dllexport) type __##call
#elif defined(API_IMPORT_SYMBOLS)
#define API_PUBLIC(type)            __declspec(dllimport) type // __cdecl __stdcall
#define API_PUBLIC_EXT(type, call)  __declspec(dllimport) type __##call
#endif

#define API_PRIVATE(type)           type // __cdecl(default) __stdcall ...
#define API_PRIVATE_EXT(type, call) type __##call

#else /* !WIN32 */

/*  For *nix builds that support visibility attribute, you can define similar behavior by
    setting default visibility to hidden by adding:

    -fvisibility=hidden (for gcc)
    or
    -xldscope=hidden (for sun cc)

    to CFLAGS, then using the API_VISIBILITY flag to "export" the same symbols the way API_EXPORT_SYMBOLS does.

    For attribute cdecl/stdcall/fastcall/pascal, they're only available on x86, i.e. x64/arm/... will ignore them.
    To test these attributes, add "-m32" in CFLAGS. One may also need to install some necessary package first, e.g.
    $ sudo apt-get install libc6-dev-i386 */

#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(API_VISIBILITY)
#define API_PUBLIC(type)            __attribute__((visibility("default"))) type
#define API_PUBLIC_EXT(type, call)  __attribute__((__##call##__, visibility("default"))) type
#else
#define API_PUBLIC(type)            type
#define API_PUBLIC_EXT(type, call)  __attribute__((__##call##__)) type
#endif

#define API_PRIVATE(type)           __attribute__((visibility("hidden"))) type
#define API_PRIVATE_EXT(type, call) __attribute__((__##call##__, visibility("hidden"))) type
#endif //!__WINDOWS__

#endif //!__IMI_API_CONFIG_H__
